﻿using System;
using System.Collections.Generic;

using System.Text;
using System.Diagnostics;
using System.IO;


namespace TestCompiler
{
    enum TResults {OK, Fail, Time, Write};
    class Program
    {
        static String[] Results = { "OK", "Fail", "Time", "Write" };
        static String TestsLocate = "tests\\", AnwersLocate = "answers\\", OutputLocate = "output\\", TestName = "";
        static Process compiler;
        static int okTest = 0, failTest = 0, writeTest =0;
        enum WorkMode {test, write}

        static Process ProcesIni(string iName)
        {
            ProcessStartInfo info = new ProcessStartInfo(iName);
            compiler = new Process();
            compiler.StartInfo = info;

            //что точно делает не помню, но вроде перегружаеть потоки, что бы ими можно было пользоваться извне...
            compiler.StartInfo.UseShellExecute = false;
            compiler.StartInfo.RedirectStandardOutput = true;

            return compiler;
        }

        static void About()
        {
            Console.WriteLine("tester for my Little Compiler v0.7");
            Console.WriteLine("Author : Oleg \"Corwin\" Pinchuk, 236gr.");
            Console.WriteLine("Syntax : TestCompiler -l|-px|ts [-t|-o] ");
            Console.WriteLine("   -l  test token analyzer");
            Console.WriteLine("   -px  test token analyzer");
            Console.WriteLine("   -ts  test token analyzer");
            Console.WriteLine(" ");
            Console.WriteLine("   -t testing Compiler");
            Console.WriteLine("   -o write result of Compiler");

            return;
        }

        static void Main(string[] args)
        { 
            
            if (args.Length == 0)  About();            
            compiler = ProcesIni("myLittleC");
            WorkMode mode=WorkMode.test;

            switch (args[0])
            {
                case  "-l": TestName = "tokenizer\\";  break;
                case "-px": TestName = "parseExpr\\"; break;
                case "-sd": TestName = "SimpleDeclaration\\"; break;
                case "-ts": TestName = "TableSybols\\"; break;

                default:
                    About();
                    return;
            }
            if (args.Length == 2)
                switch (args[1])
                {
                    case "-o": mode = WorkMode.write; break;
                    case "-t": mode = WorkMode.test; break;
                }

            String[] Tests = Directory.GetFiles(TestsLocate + TestName);

            foreach (string T in Tests)
            {
                
                String Test = T.Substring(T.LastIndexOf("\\") + 1, T.Length - T.LastIndexOf("\\") - 1);

                try
                {
                    RunTest(args[0] + " " + T);

                       if(mode == WorkMode.write)
                       {
                             OutputTest(OutputLocate + TestName + Test, compiler.StandardOutput.ReadToEnd());
                             WriteResultTest(TResults.Write);
                       }
                       else
                           WriteResultTest(CheckResult(compiler.StandardOutput.ReadToEnd(), TestName + Test));
                      
                }
                catch(Exception ex)
                {
                    if (ex.Message == TResults.Time.ToString())
                        WriteResultTest(TResults.Time);
                    else Console.WriteLine(ex);
                }
            }
            total();            
        }
        static void OutputTest(String road, String Result)
        {
            StreamWriter outt = new StreamWriter(road);
            outt.Write(Result);
            outt.Close();
        }
        static void total()
        {
            Console.ForegroundColor = failTest > 0 ? ConsoleColor.Red : ConsoleColor.Green;
            Console.ForegroundColor = writeTest > 0 ? ConsoleColor.Yellow : Console.ForegroundColor;
            Console.WriteLine("Total Tests - {0:D}, OK Tests - {1:D}, Fail Test {2:D}", okTest + failTest, okTest, failTest);
        }

        static void WriteResultTest(TResults res)
        {
            Console.ForegroundColor = ConsoleColor.White;
            
            Console.Write("Test{0:D}: ", okTest + failTest + writeTest + 1);
            
            switch (res)
            {
                case TResults.OK: okTest++; Console.ForegroundColor = ConsoleColor.Green; break;
                case TResults.Time:
                case TResults.Fail: failTest++; Console.ForegroundColor = ConsoleColor.Red; break;
                case TResults.Write: writeTest++; Console.ForegroundColor = ConsoleColor.Yellow; break;
            }

            Console.WriteLine(Results[(int)res]);           
        }


        static void RunTest(String Args)
        {
            compiler.StartInfo.Arguments = Args;

            compiler.Start();
            if (!compiler.WaitForExit(2000))
                throw new Exception(TResults.Time.ToString());

        }
        static TResults CheckResult(String Result, String RoadToAnwer)
        {
            try
            {
                StreamReader srcFile = new StreamReader(AnwersLocate + RoadToAnwer);
                String Answer = srcFile.ReadToEnd();
                if (Result != Answer)
                {
                    OutputTest(OutputLocate + RoadToAnwer, Result);
                    return TResults.Fail;
                }
                else return TResults.OK;
            }
            catch { OutputTest(OutputLocate + RoadToAnwer, Result); return TResults.Write; ; }
        }
    }
}
